home *** CD-ROM | disk | FTP | other *** search
- /* SLIP (Serial Line IP) encapsulation and control routines.
- * Copyright 1991 Phil Karn
- *
- * Van Jacobsen header compression hooks added by Katie Stevens, UC Davis
- *
- * - Feb 1991 Bill_Simpson@um.cc.umich.edu
- * reflect changes to header compression calls
- * revise status display
- */
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "slhc.h"
- #include "slip.h"
- #include "trace.h"
- #include "commands.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: slip.c,v 1.19 1997/09/07 00:31:16 root Exp root $";
- #endif
-
- static struct mbuf *slip_decode (struct slip * sp, unsigned char c);
- static struct mbuf *slip_encode (struct mbuf * bp, int usecrc);
-
- /* Slip level control structure */
- struct slip *Slip;
-
- /* Send routine for point-to-point slip */
- int
- slip_send (bp, iface, gateway, prec, del, tput, rel)
- struct mbuf *bp; /* Buffer to send */
- struct iface *iface; /* Pointer to interface control block */
- uint32 gateway OPTIONAL; /* Ignored (SLIP is point-to-point) */
- int prec OPTIONAL;
- int del OPTIONAL;
- int tput OPTIONAL;
- int rel OPTIONAL;
- {
- #ifdef VJCOMPRESS
- register struct slip *sp;
- int type;
- #endif
-
- if (iface == NULLIF) {
- free_p (bp);
- return -1;
- }
- #ifdef VJCOMPRESS
- sp = &Slip[iface->xdev];
- if (sp->escaped & SLIP_VJCOMPR) {
- /* Attempt IP/ICP header compression */
- type = slhc_compress (sp->slcomp, &bp, TRUE);
- bp->data[0] |= uchar (type);
- }
- #endif
- return (*iface->raw) (iface, bp);
- }
-
-
- /* Send a raw slip frame */
- int
- slip_raw (iface, bp)
- struct iface *iface;
- struct mbuf *bp;
- {
- struct mbuf *bp1;
- struct slip *sp;
-
- sp = &Slip[iface->xdev];
- if (sp->usecrc == 0 || sp->tracepoll == 1 || bp->cnt != 2 || ((*bp->data & 0x0f) != 0x0e))
- dump (iface, IF_TRACE_OUT, (unsigned) sp->type, bp);
- iface->rawsndcnt++;
- iface->lastsent = secclock ();
-
- #if 1
- if (iface->flags & LOOPBACK_AX25) {
- (void) pullchar (&bp);
- if (net_route (iface, 9, bp) != 0)
- free_p (bp);
- return 0;
- }
- #endif
- if ((bp1 = slip_encode (bp, sp->usecrc)) == NULLBUF)
- return -1;
-
- if (iface->trace & IF_TRACE_RAW)
- raw_dump (iface, -1, bp1);
- return sp->send (iface->dev, bp1);
- }
-
-
- /* Encode a packet in SLIP format */
- static
- struct mbuf *
- slip_encode (bp, usecrc)
- struct mbuf *bp;
- int usecrc;
- {
- struct mbuf *lbp; /* Mbuf containing line-ready packet */
- register unsigned char *cp;
- int c, crc, done;
- struct mbuf **bpp = &bp;
-
- /* Allocate output mbuf that's twice as long as the packet.
- * This is a worst-case guess (consider a packet full of FR_ENDs!)
- */
- lbp = alloc_mbuf ((int16) ((2 * len_p (bp)) + 3));
- if (lbp == NULLBUF) {
- /* No space; drop */
- free_p (bp);
- return NULLBUF;
- }
- cp = lbp->data;
-
- /* Flush out any line garbage */
- *cp++ = FR_END;
-
- /* Set crc to zero */
- crc = 0;
- done = 0;
-
-
- /* Copy input to output, escaping special characters */
- while (1) { /*lint !e716 !e774 */
- c = PULLCHAR (bpp);
- if (c == -1) { /* If we reached the end of the data */
- if (!usecrc) /* and we don't use a CRC, */
- break; /* we're done... */
- c = crc;/* otherwise, encode the crc as well */
- done = 1;
- } else /* A regular data char, calculate crc */
- crc ^= c;
- switch (c) {
- case FR_ESC:
- *cp++ = FR_ESC;
- *cp++ = T_FR_ESC;
- break;
- case FR_END:
- *cp++ = FR_ESC;
- *cp++ = T_FR_END;
- break;
- default:
- *cp++ = uchar (c);
- }
- if (done)
- break;
- }
- *cp++ = FR_END;
- lbp->cnt = (int16) (cp - lbp->data);
- return lbp;
- }
-
-
- /*lint -esym(18,slip_decode) */
- /* Process incoming bytes in SLIP format
- * When a buffer is complete, return it; otherwise NULLBUF
- */
- static struct mbuf *
- slip_decode (sp, c)
- register struct slip *sp;
- unsigned char c; /* Incoming character */
- {
- struct mbuf *bp;
- #ifdef POLLEDKISS
- struct mbuf *bp1;
- #endif
-
- switch (uchar (c)) {
- case FR_END:
- bp = sp->rbp_head;
- sp->rbp_head = NULLBUF;
- #ifdef POLLEDKISS
- if (sp->polled) {
- sp->rx = 0;
- ksignal (&sp->rx, 1); /* tell the poller we're done */
- }
- if (sp->usecrc) {
- if (bp) {
- /* Check the crc. After an ex-or of data and checksum
- * the result should be 0 - WG7J
- */
- if (sp->rxcrc) {
- free_p (bp);
- bp = NULLBUF;
- }
- /* If valid, delete the crc byte from the data */
- /* If the length of the last mbuf in chain becomes
- * zero, we must delete it. Otherwise upper level code
- * thinks we lost connection - OH2BNS
- */
- else if (--sp->rbp_tail->cnt == 0) {
- for (bp1 = bp; bp1->next->cnt != 0; bp1 = bp1->next) ;
- free_p (bp1->next);
- bp1->next = NULLBUF;
- }
- }
- }
- #endif
- return bp; /* Will be NULLBUF if empty frame */
- case FR_ESC:
- sp->escaped |= SLIP_FLAG;
- return NULLBUF;
- default:
- break;
- }
- if (sp->escaped & SLIP_FLAG) {
- /* Translate 2-char escape sequence back to original char */
- sp->escaped &= ~SLIP_FLAG;
- switch (uchar (c)) {
- case T_FR_ESC:
- c = FR_ESC;
- break;
- case T_FR_END:
- c = FR_END;
- break;
- default:
- sp->errors++;
- break;
- }
- }
- /* We reach here with a character for the buffer;
- * make sure there's space for it
- */
- if (sp->rbp_head == NULLBUF) {
- /* Allocate first mbuf for new packet */
- if ((sp->rbp_tail = sp->rbp_head = alloc_mbuf (SLIP_ALLOC)) == NULLBUF)
- return NULLBUF; /* No memory, drop */
- sp->rcp = (char *) sp->rbp_head->data;
- #ifdef POLLEDKISS
- /* If polled kiss, signal poller that we are receiving a packet */
- if (sp->polled)
- sp->rx = 1;
- if (sp->usecrc) /* clear the crc - WG7J */
- sp->rxcrc = 0;
- #endif
- } else if (sp->rbp_tail->cnt == SLIP_ALLOC) {
- /* Current mbuf is full; link in another */
- if ((sp->rbp_tail->next = alloc_mbuf (SLIP_ALLOC)) == NULLBUF) {
- /* No memory, drop whole thing */
- free_p (sp->rbp_head);
- sp->rbp_head = NULLBUF;
- return NULLBUF;
- }
- sp->rbp_tail = sp->rbp_tail->next;
- sp->rcp = (char *) sp->rbp_tail->data;
- }
- /* Store the character, increment fragment and total
- * byte counts
- */
- *sp->rcp++ = (char) c;
- sp->rbp_tail->cnt++;
- #ifdef POLLEDKISS
- /* If this interface uses CRC, adjust the crc */
- if (sp->usecrc)
- sp->rxcrc ^= (char) c;
- #endif
- return NULLBUF;
- }
-
-
- /* Process SLIP line input */
- void
- asy_rx (xdev, p1, p2)
- int xdev;
- void *p1 OPTIONAL;
- void *p2 OPTIONAL;
- {
- int c;
- struct mbuf *bp = (struct mbuf *) 0;
- register struct slip *sp;
- int cdev;
-
- server_disconnect_io ();
- sp = &Slip[xdev];
- cdev = sp->iface->dev;
-
- while ((c = sp->get (cdev)) != -1) {
- if ((bp = slip_decode (sp, uchar(c))) == NULLBUF)
- continue; /* More to come */
- #ifdef VJCOMPRESS
- if (sp->iface->trace & IF_TRACE_RAW)
- raw_dump (sp->iface, IF_TRACE_IN, bp);
-
- if (sp->escaped & SLIP_VJCOMPR) {
- if ((c = bp->data[0]) & SL_TYPE_COMPRESSED_TCP) {
- if (slhc_uncompress (sp->slcomp, &bp) <= 0) {
- free_p (bp);
- sp->errors++;
- continue;
- }
- } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
- bp->data[0] &= 0x4f;
- if (slhc_remember (sp->slcomp, &bp) <= 0) {
- free_p (bp);
- sp->errors++;
- continue;
- }
- }
- }
- #endif
- if (net_route (sp->iface, sp->type, bp) != 0) {
- free_p (bp);
- bp = 0;
- }
- }
- if (bp)
- free_p (bp);
- }
-
-
-
- /* Show serial line status */
- void
- slip_status (iface)
- struct iface *iface;
- {
- struct slip *sp;
-
- if (iface->xdev > SLIP_MAX)
- /* Must not be a SLIP device */
- return;
-
- sp = &Slip[iface->xdev];
- if (sp->iface != iface)
- /* Must not be a SLIP device */
- return;
-
- tprintf (" IN: %lu pkts\n", iface->rawrecvcnt);
- #ifdef VJCOMPRESS
- slhc_i_status (sp->slcomp);
- #endif
- tprintf (" OUT: %lu pkts\n", iface->rawsndcnt);
- #ifdef VJCOMPRESS
- slhc_o_status (sp->slcomp);
- #endif
- }
-